#include "Classification.h"
#include "Team.h"
#include "ZStream.h"
#include "ServiceProvider.h"
#include "GameSettings.h"
#include "Match.h"

#include <algorithm>
#include <cassert>
#include <iterator>

bool CompareScore(const TeamScore& t1, const TeamScore& t2)
{
	if(t1.m_score != t2.m_score)
		return t1.m_score > t2.m_score;

	const int difference1 = t1.m_outGoals - t1.m_inGoals;
	const int difference2 = t2.m_outGoals - t2.m_inGoals;

	if(difference1 != difference2)
		return difference1 > difference2;

	if(t1.m_outGoals != t2.m_outGoals)
		return t1.m_outGoals > t2.m_outGoals;

	return t1.m_team->GetName() < t2.m_team->GetName();
}

Classification::Classification(ServiceProvider* i_sp) : m_sp(i_sp)
{
	assert(m_sp);
}

void Classification::Clear()
{
	m_teamScores.clear();
	m_matchHistory.clear();
}

void Classification::Initialize(const TeamVec& i_teams)
{
	TeamScore record;
	record.m_drawMathes = 0;
	record.m_inGoals = 0;
	record.m_lostMatches = 0;
	record.m_outGoals = 0;
	record.m_score = 0;
	record.m_winMatches = 0;

	m_matchHistory.clear();

	m_teamScores.clear();
	m_teamScores.reserve(i_teams.size());

	for(size_t i = 0; i < i_teams.size(); ++i)
	{
		record.m_team = i_teams[i];
		m_teamScores.push_back(record);
	}
}

void Classification::Update(const MatchVec& i_matchScore)
{

	for(MatchVecCIt it = i_matchScore.begin(); it != i_matchScore.end(); ++it)
	{
		TeamScoreCollection::iterator team1Score = std::find_if(m_teamScores.begin(), m_teamScores.end(), CompareTeamPtr(it->GetTeam(0)));
		TeamScoreCollection::iterator team2Score = std::find_if(m_teamScores.begin(), m_teamScores.end(), CompareTeamPtr(it->GetTeam(1)));

		assert(team1Score != m_teamScores.end() && team2Score != m_teamScores.end());

		team1Score->m_outGoals += it->GetGoals(0);
		team2Score->m_outGoals += it->GetGoals(1);

		team1Score->m_inGoals += it->GetGoals(1);
		team2Score->m_inGoals += it->GetGoals(0);

		bool team1win = (it->GetGoals(0) > it->GetGoals(1));
		bool team2win = (it->GetGoals(0) < it->GetGoals(1));

		if(!team1win && !team2win) // check for draw
		{
			++(team1Score->m_drawMathes);
			++(team2Score->m_drawMathes);

			team1Score->m_score += 1;
			team2Score->m_score += 1;
		}
		else
		{
			TeamScoreCollection::iterator& theWinner = team1win ? team1Score : team2Score;
			TeamScoreCollection::iterator& theLoser = team1win ? team2Score : team1Score;

			++(theWinner->m_winMatches);
			++(theLoser->m_lostMatches);
			theWinner->m_score += 3;
		}

	}

	std::sort(m_teamScores.begin(), m_teamScores.end(), CompareScore);

	Utilities::Append(m_matchHistory, i_matchScore);
}

TeamVec Classification::GetSortedTeams() const
{
	TeamVec o_Teams;

	TeamScoreCollection::const_iterator it = m_teamScores.begin();
	for(; it != m_teamScores.end(); ++it)
	{
		o_Teams.push_back((*it).m_team);
	}
	return o_Teams;
}

ZStream& Classification::Serialize(ZStream& o_stream)
{
	o_stream.WriteOpenTag("Classification");

	o_stream.WriteAttribute("Played", m_matchHistory.size());

	MatchVecIt it = m_matchHistory.begin();
	MatchVecIt end = m_matchHistory.end();

	for(; it != end; ++it)
	{
		(*it).Serialize(o_stream);
	}

	o_stream.WriteCloseTag("Classification");
	return o_stream;
}

ZStream& Classification::Deserialize(ZStream& i_stream)
{
	i_stream.SkipLine();

	size_t size;
	i_stream.ReadAttribute(size);

	MatchVec matchTmp;

	for(size_t i = 0; i < size; ++i)
	{
		Match match(m_sp);
		match.Deserialize(i_stream);
		matchTmp.push_back(match);
	}

	Update(matchTmp);
	
	i_stream.SkipLine();
	return i_stream;
}

